package main

import (
	"fmt"
	"log"
)

type Grids struct {
	Cols, Rows int
	Start      *Node
	End        *Node
	Nodes      [][]*Node
	OpenList   *List //打开列表
	CloseList  *List //关闭列表
}

//创建新的表格
func NewGrids(cols, rows int) *Grids {
	log.Println("初始化地图")
	grids := &Grids{
		Cols:  cols,
		Rows:  rows,
		Start: &Node{},
		End:   &Node{},
	}
	grids.Nodes = make([][]*Node, 0, cols)
	for i := 0; i < cols; i++ {
		nodes := make([]*Node, 0, rows)
		for j := 0; j < rows; j++ {
			node := NewNode(i, j)
			node.Index = j + i*rows
			nodes = append(nodes, node)
		}
		grids.Nodes = append(grids.Nodes, nodes)
	}
	log.Println("初始化地图完成, 共", cols*rows, "个点")
	return grids
}

//初始化关闭列表
func (this *Grids) initCloseList() {
	//关闭列表
	this.CloseList = &List{Cols: this.Cols, Rows: this.Rows}
	this.CloseList.Value = make([][]*ListAttr, 0, this.Cols)
	for i := 0; i < this.Cols; i++ {
		listAttr := make([]*ListAttr, 0, this.Rows)
		for j := 0; j < this.Rows; j++ {
			lattr := &ListAttr{Node: NewNode(i, j)}
			listAttr = append(listAttr, lattr)
		}
		this.CloseList.Value = append(this.CloseList.Value, listAttr)
	}
}

//初始化打开列表
func (this *Grids) initOpenList() {
	//打开列表
	this.OpenList = &List{Cols: this.Cols, Rows: this.Rows}
	this.OpenList.Value = make([][]*ListAttr, 0, this.Cols)
	for i := 0; i < this.Cols; i++ {
		listAttr := make([]*ListAttr, 0, this.Rows)
		for j := 0; j < this.Rows; j++ {
			lattr := &ListAttr{Node: NewNode(i, j)}
			lattr.G = getMapExpense(i, j, DIR_ORIGIN)
			lattr.H = getDistance(i, j, this.End.X, this.End.Y)
			lattr.F = lattr.G + lattr.H
			listAttr = append(listAttr, lattr)
		}
		this.OpenList.Value = append(this.OpenList.Value, listAttr)
	}
	this.OpenList.Length = 0
}

/**
 * 获取二维索引处的节点
 */
func (this *Grids) Node(x, y int) *Node {
	return this.Nodes[x][y]
}

/**
 * 设置（x, y)二维索引处的节点是否可以行走
 * @param walkable true为可行走
 */
func (this *Grids) SetWaklable(x, y int, walkable bool) {
	this.Node(x, y).Walkable = walkable
}

// 移除打开列表的一个元素
func (this *Grids) removeOpenList(x, y int) {
	if this.OpenList.Get(x, y).IsExist {
		this.OpenList.Get(x, y).IsExist = false
		this.OpenList.Length--
	}
}

//打印矩阵
func (this *Grids) Print() {
	nodes := this.Nodes
	for i := 0; i < this.Cols; i++ {
		for j := 0; j < this.Rows; j++ {
			point := nodes[i][j]
			if point.Walkable {

			}
			fmt.Print(point.Index, " ")
		}
		fmt.Println("")
	}
}

// 添加一个新的节点
func (this *Grids) addNewOpenList(x, y, newX, newY, dir int) {
	if this.isCanPass(newX, newY) {
		if this.OpenList.Get(newX, newY).IsExist {
			if this.OpenList.Get(x, y).G+getMapExpense(newX, newY, dir) < this.OpenList.Get(newX, newY).G {
				this.setFatherDir(newX, newY, dir)
				this.setCost(newX, newY, x, y, dir)
			}
		} else {
			this.addOpenList(newX, newY)
			this.setFatherDir(newX, newY, dir)
			this.setCost(newX, newY, x, y, dir)
		}
	}
}

// 设置消耗值
func (this *Grids) setCost(x, y, ex, ey, dir int) {
	point := this.OpenList.Get(x, y)
	point.G = this.OpenList.Get(ex, ey).G + getMapExpense(x, y, dir)
	point.H = getDistance(x, y, ex, ey)
	point.F = point.G + point.H
}

// 设置父节点方向
func (this *Grids) setFatherDir(x, y, dir int) {
	this.OpenList.Get(x, y).Parent = this.Node(x, y).node
}

// 添加关闭列表
func (this *Grids) addCloseList(x, y int) {
	this.CloseList.Get(x, y).IsExist = true
	this.CloseList.Length++
	this.CloseList.NowPoint = append(this.CloseList.NowPoint, []int{x, y})
}

// 添加打开列表
func (this *Grids) addOpenList(x, y int) {
	if this.OpenList.Get(x, y).IsExist == false {
		this.OpenList.Get(x, y).IsExist = true
		this.OpenList.Length++
		this.OpenList.NowPoint = append(this.OpenList.NowPoint, []int{x, y})
	}
}

// 判断一个点是否可以通过
func (this *Grids) isCanPass(x, y int) bool {
	// 超出边界
	if x < 0 || x >= this.Cols || y < 0 || y > this.Rows {
		return false
	}
	// 地图不通
	if !this.Node(x, y).Walkable {
		return false
	}
	// 在关闭列表中
	if this.isInCloseList(x, y) {
		return false
	}
	return true
}

// 判断一点是否在关闭列表中
func (this *Grids) isInCloseList(x, y int) bool {
	return this.CloseList.Get(x, y).IsExist
}
